package com.megaspacevr.controller;

import com.megaspacevr.entity.AdminUser;
import com.megaspacevr.entity.Result;
import com.megaspacevr.entity.vo.AdminLoginVO;
import com.megaspacevr.entity.vo.AdminUpdateVO;
import com.megaspacevr.service.AdminUserService;
import com.megaspacevr.utils.JwtUtil;
import com.megaspacevr.utils.ResultUtil;
import com.megaspacevr.utils.ThreadLocalUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Pattern;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 管理员表 前端控制器
 * </p>
 *
 * @author yezi
 * @since 2025-06-17
 */
@Slf4j
@RestController
@Validated
@RequestMapping("/adminUser")
public class AdminUserController {

    @Autowired
    private AdminUserService adminUserService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    
    // 直接创建BCryptPasswordEncoder实例，避免依赖注入问题
    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    // 登录方法
    @PostMapping("/login")
    public Result<AdminLoginVO> login(@Pattern(regexp="^\\S{5,16}$")String username,
                                      @Pattern(regexp="^\\S{5,16}$")String password,
                                      HttpServletRequest request) {
        log.info("管理员登录尝试，用户名: {},密码：{}", username, password);
        
        //根据账号查找管理员
        AdminUser loginAdmin = adminUserService.findByUsername(username);
        log.info("管理员信息", loginAdmin);

        //判断账号是否存在
        if (loginAdmin == null) {
            log.warn("登录失败，用户不存在: {}", username);
            return ResultUtil.fail("该用户不存在！");
        }
        
        //判断账号状态
        if (!"active".equals(loginAdmin.getStatus())) {
            log.warn("登录失败，账号已被禁用: {}", username);
            return ResultUtil.fail("账号已被禁用！");
        }
        
        //判断密码是否正确（使用BCrypt验证）
        log.info("开始验证密码 - 原始密码: {}, 加密密码: {}", password, loginAdmin.getPassword());
        boolean passwordMatches = passwordEncoder.matches(password, loginAdmin.getPassword());
        log.info("密码验证结果: {}", passwordMatches);
        
        if(passwordMatches) {
            Map<String, Object> claims = new HashMap<>();
            claims.put("id", loginAdmin.getId());
            claims.put("username", loginAdmin.getUsername());
            claims.put("status", loginAdmin.getStatus());
            
            // 生成token，设置1小时过期
            String token = JwtUtil.genToken(claims, 1000L * 60 * 60);
            
            // 获取状态信息
            String status = loginAdmin.getStatus();
            
            // 创建返回对象
            AdminLoginVO loginVO = new AdminLoginVO(token, status);
            
            // 存储到Redis，设置过期时间
            ValueOperations<String, String> Operations = stringRedisTemplate.opsForValue();
            Operations.set(token, token, 1, TimeUnit.HOURS);
            
            // 获取客户端IP地址
            String clientIp = getClientIpAddress(request);
            
            // 更新最后登录时间、IP和登录次数
            loginAdmin.setLastLoginTime(LocalDateTime.now());
            loginAdmin.setLastLoginIp(clientIp);
            loginAdmin.setLoginCount(loginAdmin.getLoginCount() != null ? loginAdmin.getLoginCount() + 1 : 1);
            adminUserService.updateById(loginAdmin);
            
            log.info("管理员登录成功，用户名: {}, IP: {}", username, clientIp);
            return ResultUtil.success(loginVO);
        }

        log.warn("登录失败，密码错误: {}", "登录账号：",username, "输入密码：",password);
        return ResultUtil.fail("密码错误");
    }

    //查看管理员个人信息
    @GetMapping("/getAdminInfo")
    public Result<AdminUser> getAdminInfo() {
        Map<String, Object> map = ThreadLocalUtil.get();
        String username=(String)map.get("username");
        AdminUser admin = adminUserService.findByUsername(username);
        if (admin != null) {
            // 清空密码字段，不返回给前端
            admin.setPassword(null);
            return ResultUtil.success(admin);
        }
        return ResultUtil.fail("用户不存在");
    }
    
    //修改管理员个人信息
    @PutMapping("/updateAdminInfo")
    public Result<String> updateAdminInfo(@Valid @RequestBody AdminUpdateVO updateVO) {
        // 从ThreadLocal获取当前登录用户信息
        Map<String, Object> map = ThreadLocalUtil.get();
        String username = (String) map.get("username");
        Long adminId = ((Number) map.get("id")).longValue();
        
        log.info("管理员 {} 请求修改个人信息: {}", username, updateVO);
        
        // 查询当前用户信息
        AdminUser currentAdmin = adminUserService.findByUsername(username);
        if (currentAdmin == null) {
            return ResultUtil.fail("用户不存在");
        }
        
        // 更新用户信息
        currentAdmin.setRealName(updateVO.getRealName());
        currentAdmin.setEmail(updateVO.getEmail());
        currentAdmin.setPhone(updateVO.getPhone());
        currentAdmin.setUpdatedAt(LocalDateTime.now());
        
        // 保存到数据库
        boolean success = adminUserService.updateById(currentAdmin);
        if (success) {
            log.info("管理员 {} 个人信息修改成功", username);
            return ResultUtil.success("个人信息修改成功");
        } else {
            log.error("管理员 {} 个人信息修改失败", username);
            return ResultUtil.fail("个人信息修改失败");
        }
    }
    
    
    /**
     * 生成BCrypt加密密码
     */
    @GetMapping("/generatePassword")
    public Result<Map<String, Object>> generatePassword(String rawPassword) {
        if (rawPassword == null || rawPassword.isEmpty()) {
            rawPassword = "admin123"; // 默认密码
        }
        
        Map<String, Object> result = new HashMap<>();
        
        // 生成多个BCrypt密码进行对比
        for (int i = 1; i <= 3; i++) {
            String encoded = passwordEncoder.encode(rawPassword);
            boolean matches = passwordEncoder.matches(rawPassword, encoded);
            result.put("password" + i, encoded);
            result.put("matches" + i, matches);
            log.info("生成密码{}: {} -> {}, 验证: {}", i, rawPassword, encoded, matches);
        }
        
        // 测试数据库中的密码
        String dbPassword = "$2a$10$7JB720yubVSeLan6Zzg2XO8W1l0wJlS2Q2HHMb4ZLWt7Uef.Lsc.i";
        boolean dbMatches = passwordEncoder.matches(rawPassword, dbPassword);
        result.put("dbPassword", dbPassword);
        result.put("dbMatches", dbMatches);
        
        log.info("原始密码: {}", rawPassword);
        log.info("数据库密码: {}", dbPassword);
        log.info("数据库密码验证: {}", dbMatches);
        
        return ResultUtil.success(result);
    }
    
    /**
     * 测试BCrypt密码验证
     */
    @GetMapping("/testPassword")
    public Result<String> testPassword() {
        String rawPassword = "admin123";
        String encodedPassword = "$2a$10$7JB720yubVSeLan6Zzg2XO8W1l0wJlS2Q2HHMb4ZLWt7Uef.Lsc.i";
        
        log.info("测试密码验证");
        log.info("原始密码: {}", rawPassword);
        log.info("加密密码: {}", encodedPassword);
        
        boolean matches = passwordEncoder.matches(rawPassword, encodedPassword);
        log.info("验证结果: {}", matches);
        
        // 生成新的加密密码进行对比
        String newEncoded = passwordEncoder.encode(rawPassword);
        log.info("新生成的加密密码: {}", newEncoded);
        boolean newMatches = passwordEncoder.matches(rawPassword, newEncoded);
        log.info("新密码验证结果: {}", newMatches);
        
        return ResultUtil.success("验证结果: " + matches + ", 新密码验证: " + newMatches);
    }
    
    /**
     * 获取客户端真实IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }
        
        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }
        
        String proxyClientIp = request.getHeader("Proxy-Client-IP");
        if (proxyClientIp != null && !proxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(proxyClientIp)) {
            return proxyClientIp;
        }
        
        String wlProxyClientIp = request.getHeader("WL-Proxy-Client-IP");
        if (wlProxyClientIp != null && !wlProxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(wlProxyClientIp)) {
            return wlProxyClientIp;
        }
        
        return request.getRemoteAddr();
    }
}
